﻿using CodeGen.TS.Generation.Members;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace CodeGen.TS.Generation.Generators
{
    public class InterfaceGenerator : ICodeGenerator
    {

        ICodeGenerator baseInterfaceGenerator;


        public BaseTypeMode BaseTypeMode
        {
            get;
            set;
        }

        public string OutputFileName
        {
            get;
            set;
        }

        private Type type;
        public Type Type
        {
            get { return type; }
            set
            {
                type = value;
                if (newTypeName == null)
                    newTypeName = value.Name;
            }
        }
        private string baseInted = Properties.Settings.Default.IndentString;
        public string BaseIntend { get { return baseInted; } set { baseInted = value; } }

        public bool UseObservable { get; set; }

        private string newTypeName;
        public string NewTypeName
        {
            get
            {
                return newTypeName;
            }
            set
            {
                newTypeName = value;
            }
        }

        public string ModulName
        {
            get;
            set;
        }

        public int RecursionLevel
        {
            get;
            set;
        }

        private bool isPreparedForOutput = false;
        public bool IsPreparedForOutput
        {
            get { return isPreparedForOutput; }
        }


        private IList<TSPropertyInfo> PropertyInfos { get; set; }

        public string GenerateOutput()
        {
            string extendsImplementsString = "";
            if (baseInterfaceGenerator != null)
            {
                extendsImplementsString = "implements " + (baseInterfaceGenerator.ModulName == null || baseInterfaceGenerator.ModulName == this.ModulName ? "" : baseInterfaceGenerator.ModulName + ".") + baseInterfaceGenerator.NewTypeName;
            }
            string returnString = BaseIntend + (ModulName==null? "": "export ") + "interface " + newTypeName + extendsImplementsString + "{";

            returnString += GenerateFields(PropertyInfos);
            returnString += Environment.NewLine + BaseIntend + "}";
            return returnString;
        }

        string GenerateFields(IEnumerable<TSPropertyInfo> properties)
        {
            string returnString = "";
            foreach (var property in properties)
            {
                returnString += Environment.NewLine + BaseIntend + Properties.Settings.Default.IndentString + property.GetDefinition( false);
            }
            return returnString;
        }



        public void PrepareForOutput(bool allowRecursion)
        {
            this.PropertyInfos = CodeGenerationHelper.GetTSFields(this, allowRecursion);
            if (BaseTypeMode == TS.BaseTypeMode.Exclude && type.BaseType != null && type.BaseType != typeof(object) && allowRecursion)
            {
                this.baseInterfaceGenerator = Output.TypeGeneratorFactory.GetGenerator(type.BaseType, this.UseObservable);
                if (this.baseInterfaceGenerator == null)
                {
                    this.baseInterfaceGenerator = new InterfaceGenerator();
                    this.baseInterfaceGenerator.Type = this.type.BaseType;
                    this.CopyToDependend(this.baseInterfaceGenerator);
                    if (this.type.Namespace == this.type.BaseType.Namespace)
                    {
                        this.baseInterfaceGenerator.ModulName = this.ModulName;
                    }
                    else
                    {
                        this.baseInterfaceGenerator.ModulName = this.type.BaseType.Namespace;
                    }
                    Output.TypeGeneratorFactory.RegisterGenerator(this.baseInterfaceGenerator);
                }

            }
            isPreparedForOutput = true;
        }

    }
}
